package aria

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"time"

	"gitee.com/AlmondLee/gf-tools/function/param"
	"gitee.com/AlmondLee/gf-tools/mutex"

	// . "gitee.com/AlmondLee/gf-tools/arg"
	. "gitee.com/AlmondLee/gf-tools/tst"

	"github.com/gogf/gf/encoding/gparser"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gfile"
	"github.com/gogf/gf/os/glog"
	"github.com/gogf/gf/util/gconv"
)

// var ConPool chan uint64
type Aria struct {
	blockSize int
	j		  int
	retry	  int
	// Dir			 string
	split		 int
	blockCount	 int
	splitPool	 *mutex.Mutex
	threadStatus *mutex.Mutex
	logWriter	 *mutex.Mutex
	url			 string
	UserAgent	 string
	Dir			 string
	// DownLoadDir string
	FileName string
	AbsPath  string
	// url []string
}

func init() {
}

func getOpt(options g.Map) {
}

func New(url string, Args g.Map) (this *Aria) {
	// defer Recover()
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	this = new(Aria)
	// ConPool = make(chan uint64, gconv.Int(Parser.GetOpt(`j`)))
	// this.j=j
	// this.split=s

	// if len(numArgs) == 0 {
	// numArgs = make([]int, 2)
	// numArgs[0] = 4
	// numArgs[1] = 4

	// }
	this.url = url
	this.blockSize = 10485760

	if this.AcceptRanges() {
		For(this.blockCount, func(id int) {
			// fmt.Println(i, id)
			// i--
		})
	}

	funcArg := param.New(Args)
	// con, err :=
	// clint.Timeout(15 * time.Second).Ge
	// req, err := http.NewRequest("HEAD", url, nil)
	// Err(err)
	// resp, err := req.Trailer
	// Err(err)
	this.threadStatus = mutex.New(funcArg.GetOptInt(`j`))
	this.logWriter = mutex.New()
	// this.splitPool = mutex.New(getArg())
	// this.url = make([]string, 0)

	// panic(`nil`)
	glog.Panic()
	return
}

func (this *Aria) AcceptRanges() bool {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	if r, err := g.Client().
		// SetHeader("User-Agent", this.UserAgent).
		// SetHeader("User-Agent", this.UserAgent).
		Get(this.url); err != nil {
		Fatal(err)
	} else {
		defer r.Close()
		// gfile.PutBytes("/Users/john/Temp/cover.png", r.ReadAll())
		// E(r.StatusCode)
		if r.StatusCode != 200 {
			Fatal(r.StatusCode)
		}

		if r.Header.Get(`Accept-Ranges`) != `bytes` {
			P(`服务端不允许以bytes的形式获取文件, 使用单线程下载`)
			return false
		}

		this.FileName = path.Base(this.url[:])
		this.AbsPath = this.Dir + this.FileName
		// E(gconv.Int(r.Header.Get(`Content-Length`)) / this.blockSize)
		this.blockCount = int(gconv.Uint64(r.Header.Get(`Content-Length`)) / gconv.Uint64(this.blockSize))
		if this.blockCount == 0 {
			P(`文件不大, 使用单线程下载`)
			this.blockCount = 1
			return false
		}

		this.blockCount++
		// panic(`nil`)
		// Err(errors.New(``))
	}

	return false
}

// func (this *Aria) AppendDownLoadUrl(url string) {
// this.url = append(this.url, url)
// }

// func (this *Aria) AppendDownLoadUrl(url string) {
// }

func (this *Aria) Download() (err error) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	hasDownLoaded, err := gfile.ScanDir(`/tmp`, `aria.mp4`, false)
	if len(hasDownLoaded) != 0 {
		hasDownLoaded, err = gfile.ScanDir(`/tmp`, `aria.mp4.aria`, false)
		if err != nil {
			return err
		}

		if len(hasDownLoaded) != 0 {
			P(`文件下载过, 但未完成`)
		} else {
			P(`文件下载过`)
			return

		}
	} else {
		gfile.PutBytes(filepath.Join(this.Dir, this.FileName), nil) //gconv.String(inf))
	}
	// var downLoadLog *os.File
	// if downLoadLog, err = os.OpenFile(`/tmp/aria.mp4.aria`, os.O_RDWR|os.O_CREATE, 0666); err != nil {
	//	tst.Warn(err)
	//	return
	// }
	// defer downLoadLog.Close()

	var f *os.File
	if f, err = os.OpenFile(`/tmp/aria.mp4`, os.O_RDWR|os.O_CREATE, 0666); err != nil {
		Warn(err)
		return
	}
	defer f.Close()
	// this
	// for

	// file.WriteAt()

	return
}

func (this *Aria) downBlock(threadId int) (err error) {
	this.splitPool.Lock()
	defer this.threadStatus.SentCompleteSingnal()
	defer this.threadStatus.UnLock()
	start := this.blockSize * threadId
	end := this.blockSize + start
	rangeBlock := fmt.Sprintf("%d-%d", start, end)
	if r, err := g.Client().
		SetHeader("User-Agent", this.UserAgent).
		// SetHeader("User-Agent", gconv.String(threadId)).
		SetHeader("", "bytes="+rangeBlock).
		// SetHeader("User-Agent", this.UserAgent).
		Get(this.url); err != nil {
		panic(err)
	} else {
		defer r.Close()
		gfile.PutBytes("/Users/john/Temp/cover.png", r.ReadAll())
	}

	return
}

// func Curl(password string) {
// func Curl(Prase interface{}) {
func Curl(line uint64, password string) {

	// tst.Pl(Prase)
	// fmt.Println("vim-go")
	clint := g.Client()
	clint.SetBasicAuth(`admin`, password)

	con, err := clint.Timeout(3 * time.Second).Get("http://192.168.123.1")
	Err(err)
	// if err != nil {
	//	Warn(err)
	//	panic(err)
	// }
	// tst.Pl(con)
	if con.StatusCode == 401 {
		// return false
		// ConPool <- 0
		// tst.Warn(errors.New(`unAuthorized`))
	}
	Pl(con.StatusCode)
	Pl(`password:`, password)
	Pl(con.ReadAllString())
	// return true
	// ConPool <- line
}

func (this *Aria) AppendToLogFile(log interface{}) {
	defer recover()

	this.logWriter.Lock()

	logs, err := gparser.LoadJson(gfile.GetBytes(filepath.Join(this.Dir, this.FileName)), false)
	// logs, err := gjson.Load(filepath.Join(this.Dir, this.FileName), false)
	Err(err)

	// var inf interface{}
	switch t := log.(type) {
	case g.Map:
		// inf
		for key, val := range t {
			err := logs.Set(key, val)
			Warn(err)
		}

	case string, byte:
		// inf = t
		return
	}

	// fileList = append(fileList, sli)
	// if downLoadLog, err = os.OpenFile(`/tmp/aria.mp4.aria`, os.O_RDWR|os.O_CREATE, 0666); err != nil {
	t, _ := logs.MarshalJSON()
	gfile.PutBytes(filepath.Join(this.Dir, this.FileName), t) //gconv.String(inf))
	this.logWriter.UnLock()
}
